<?php
namespace app\common\lib;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\RequestException;
class Guzzle
{
    private static $guzzle = [];
    public static  $errors = '' ;
    public static  $timeout = 120;

    /**
     * @desc 获取错误信息
     * @return string
     */
    static function getError()
    {
        return self::$errors;
    }

    public static function setTimeOut($time)
    {
        self::$timeout = $time;
    }
    /**
     * @desc 释放资源
     * @return bool
     */
    public static function closeAllConns()
    {
        if (count(self::$guzzle) === 0) {
            return true;
        }
        foreach (self::$guzzle as $conn){
            $conn = null;
        }
    }

    /**
     * @desc 实例化guzzle(单例)
     * @param $baseUri (http://www.xxx.com)
     * @return bool
     */
    private static function init($baseUri)
    {
        if (!isset(self::$guzzle[$baseUri])) {
            if (empty($baseUri)) {
                return false;
            }
            self::$guzzle[$baseUri] = new Client([
                'base_uri' => $baseUri,
                'timeout'  => self::$timeout,
                // https请求
                'verify' => strpos($baseUri, 'https:') == false ? true : false,
            ]);
        }
        return true;
    }

    /**
     * @desc 获取guzzle实例
     * @param $baseUri
     * @return bool|mixed
     */
    public static function getGuzzle($baseUri)
    {
        $ret = Guzzle::init($baseUri);
        if ($ret == false) {
            return false;
        }
        return self::$guzzle[$baseUri];
    }

    /**
     * @desc post请求
     * @param string $baseUri   设置uri http://api.a45.me
     * @param string $path   请求api /front/login
     * @param array $postData   请求数据
     * @param array $headers  请求头
     * @param string $type   请求类型 json
     * @param array $cookie  请求cookies
     * @return mixed
     * @throws \Exception
     */
    public static function post($baseUri, $path, $postData = [], $headers = [], $type = 'json', $cookie = [])
    {
        $domain = parse_url($baseUri,PHP_URL_HOST);
        $cookie = CookieJar::fromArray($cookie,$domain);
        $guzzle_ins = Guzzle::getGuzzle($baseUri);
        try {
            switch ($type) {
                //json格式发送
                case 'json':
                    $data = [
                        'headers' => $headers,
                        'json'    => $postData,
                        'cookies' => $cookie,
                    ];
                    break;
                //fromData格式发送
                case 'fromData':
                    $data = [
                        'headers'     => $headers,
                        'form_params' => $postData,
                        'cookies'     => $cookie,
                    ];
                    break;
                //body格式发送
                case 'body':
                    $data = [
                        'headers' => $headers,
                        'body'    => $postData,
                    ];
                    break;
                //multipart格式发送
                case 'multipart':
                    $data = [
                        'headers'   => $headers,
                        'multipart' => $postData,
                    ];
                    break;
                 //默认
                default:
                    $data = [
                        'headers' => $headers,
                        'json'    => $postData,
                        'cookies' => $cookie,
                    ];
            }
            $response = $guzzle_ins->post($path, $data);
            return \GuzzleHttp\json_decode($response->getBody()->getContents(), true);
        } catch (RequestException $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,$postData,$headers);
            self::$errors = $e->getMessage();
            return false;
        } catch (\Throwable $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,$postData,$headers);
            self::$errors = $e->getMessage();
            return false;
        }
    }

    /**
     * @desc post请求(异步)
     * @param string $baseUri   设置uri
     * @param string $path  请求api
     * @param array $postData  请求数据
     * @param array $headers  请求头
     * @param string $type  请求类型 json
     * @param string $cookie   请求cookies
     * @return array|mixed
     * @throws \Exception
     */
    public static function postAsync($baseUri, $path, $postData = [], $headers = [], $type = 'json', $cookie = [])
    {
        $domain = parse_url($baseUri,PHP_URL_HOST);
        $cookie = CookieJar::fromArray($cookie,$domain);

        $guzzle_ins = Guzzle::getGuzzle($baseUri);
        $info = [];
        try {
            switch ($type) {
                //json格式发送
                case 'json':
                    $data = [
                        'headers' => $headers,
                        'json'    => $postData,
                        'cookies' => $cookie,
                    ];
                    break;
                //fromData格式发送
                case 'fromData':
                    $data = [
                        'headers'     => $headers,
                        'form_params' => $postData,
                        'cookies'     => $cookie,
                    ];
                    break;
                //body格式发送
                case 'body':
                    $data = [
                        'headers' => $headers,
                        'body'    => $postData,
                    ];
                    break;
                //multipart格式发送
                case 'multipart':
                    $data = [
                        'headers'   => $headers,
                        'multipart' => $postData,
                    ];
                    break;
                //默认
                default:
                    $data = [
                        'headers' => $headers,
                        'json'    => $postData,
                        'cookies' => $cookie,
                    ];
            }
            $promises = $guzzle_ins->postAsync($path, $data);
            // 等待响应（如果需要处理响应）
//            $promises->then(
//                function ($response) use($option) {
//                    // 请求成功，处理响应
//                    var_dump($response->getStatusCode());
//                    call_user_func($option['callback'],$response,'success',$option['param']);
//                    //echo 'Response received with status code: ' . $response->getStatusCode() . PHP_EOL;
//                },
//                function ($exception)  use($option) {
//                    // 请求失败，处理异常
//                    var_dump($exception->getMessage());
//                    call_user_func($option['callback'],$exception,'fail',$option['param']);
//                    //echo 'Error: ' . $exception->getMessage() . PHP_EOL;
//                }
//            );
            return $promises;
        } catch (RequestException $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,$postData,$headers);
            self::$errors = $e->getMessage();
            return false;
        } catch (\Throwable $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,$postData,$headers);
            self::$errors = $e->getMessage();
            return false;
        }
    }

    /**
     * @desc get请求
     * @param string $baseUri   设置uri http://api.a45.me
     * @param string $path 请求api /api/status/index?type=account_type
     * @param array $headers 请求头
     * @param array $cookie 请求头
     * @return mixed
     * @throws \Exception
     */
    public static function get($baseUri, $path, $headers = [], $cookie=[])
    {
        $domain = parse_url($baseUri,PHP_URL_HOST);
        $cookie = CookieJar::fromArray($cookie,$domain);

        $guzzle_ins = Guzzle::getGuzzle($baseUri);
        try{
            $data = [
                'headers' => $headers,
                'cookies' => $cookie,
            ];
            $response = $guzzle_ins->get($path, $data);
            $result = $response->getBody()->getContents();
            return \GuzzleHttp\json_decode($result, true);
        } catch (RequestException $e){
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,[],$headers);
            self::$errors = $e->getMessage();
            return false;
        } catch (\Throwable $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,[],$headers);
            self::$errors = $e->getMessage();
            return false;
        }
    }

    /**
     * @desc get请求(异步)
     * @param string $baseUri   设置uri
     * @param string $path 请求api
     * @param array $headers 请求头
     * @param array $cookie 请求头
     * @return mixed
     * @throws \Exception
     */
    public static function getAsync($baseUri, $path, $headers = [],$cookie=[])
    {
        $domain = parse_url($baseUri,PHP_URL_HOST);
        $cookie = CookieJar::fromArray($cookie,$domain);

        $guzzle_ins = Guzzle::getGuzzle($baseUri);
        $info = [];
        try {
            $data = [
                'headers' => $headers,
                'cookies' => $cookie,
            ];
            $promises = [$guzzle_ins->getAsync($path, $data)];
            $ret = \GuzzleHttp\Promise\Utils::any($promises);

            foreach ($ret as $k => $v){
                $info =  \GuzzleHttp\json_decode($v->getBody()->getContents(), true);   //获取server端返回值
            }
            return $info;
        } catch (RequestException $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,[],$headers);
            self::$errors = $e->getMessage();
            return false;
        } catch (\Throwable $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path,[],$headers);
            self::$errors = $e->getMessage();
            return false;
        }
    }

    /**
     * @desc get请求(并行异步)
     * @param string $baseUri   设置uri
     * @param array $path 请求api
     * @return mixed
     * @throws \Exception
     */
    public static function getAsyncAll($baseUri, $path)
    {
        $guzzle_ins = Guzzle::getGuzzle($baseUri);
        try {
            $promises = [];
            $info = [];
            if (!empty($path)) {
                foreach ($path as $value){
                    array_push($promises, $guzzle_ins->getAsync($value));
                }
            }
            $ret = \GuzzleHttp\Promise\Utils::unwrap ($promises);
            foreach ($ret as $k => $v){
                $info[] =  \GuzzleHttp\json_decode($v->getBody()->getContents(), true);   //获取server端返回值
            }
            return $info;
        } catch (RequestException $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path);
            self::$errors = $e->getMessage();
            return false;
        } catch (\Throwable $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path);
            self::$errors = $e->getMessage();
            return false;
        }
    }

    /**
     * @desc head
     * @param string $baseUri   设置uri http://api.a45.me
     * @param string $path 请求api /api/status/index
     * @param array $headers 请求头
     * @param array $cookie
     * @return mixed
     * @throws \Exception
     */
    public static function head($baseUri, $path, $headers = [], $cookie=[])
    {
        $domain = parse_url($baseUri,PHP_URL_HOST);
        $cookie = CookieJar::fromArray($cookie,$domain);

        $guzzle_ins = Guzzle::getGuzzle($baseUri);
        try{
            $data = [
                'headers'     => $headers,
                'cookies'     => $cookie,
            ];
            $response = $guzzle_ins->head($path, $data);
            $result = $response->getHeaders();
            return $result;
        } catch (RequestException $e){
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path);
            self::$errors = $e->getMessage();
            return false;
        } catch (\Throwable $e) {
            self::sendExcetionNotice($e->getMessage(),$baseUri, $path);
            self::$errors = $e->getMessage();
            return false;
        }
    }

    public static function sendExcetionNotice($message,$baseUri,$path,$postData=[],$headers=[],$type='')
    {
        $content = '请求异常通知: '."\n"."\n";
        $content .= '请求地址: '.$baseUri.$path."\n";
        $content .= '请求类型: '.$type."\n";
        $content .= '请求参数: '.json_encode($postData,256)."\n";
        $content .= '请求头: '.json_encode($headers,256)."\n";
        $content .= '异常信息: '.$message."\n";

        Common::sendFeiShuNotice($content);
    }
}
